package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.WemediaConstants;
import com.heima.common.constants.WmNewsMessageConstants;
import com.heima.common.exception.CustomException;
import com.heima.model.common.dtos.PageRequestDto;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.model.wemedia.vo.WmNewsVo;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import com.heima.wemedia.service.WmNewsService;
import com.heima.wemedia.service.WmNewsTaskService;
import com.heima.wemedia.service.WmUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import thread.WmThreadLocalUtil;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {
    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    private WmMaterialMapper wmMaterialMapper;

    @Autowired
    private WmNewsAutoScanService wmNewsAutoScanService;

    @Autowired
    private WmNewsTaskService wmNewsTaskService;

    @Override
    public ResponseResult findAll(WmNewsPageReqDto dto) {
        log.info(String.valueOf(dto));
        dto.checkParam();

        //分页查询
        Page<WmNews> page = new Page<>(dto.getPage(), dto.getSize());
        //模糊查询
        LambdaQueryWrapper<WmNews> lqw = new LambdaQueryWrapper<>();
        lqw.like(StringUtils.isNotBlank(dto.getKeyword()), WmNews::getTitle, dto.getKeyword());
        //当前用户
        lqw.eq(WmNews::getUserId, WmThreadLocalUtil.getWmUserThreadLocal().getId());
        //时间
        lqw.between(dto.getBeginPubDate() != null, WmNews::getPublishTime, dto.getBeginPubDate(), dto.getEndPubDate());
        //审核状态
        lqw.eq(dto.getStatus() != null, WmNews::getStatus, dto.getStatus());
        //频道
        lqw.eq(dto.getChannelId() != null, WmNews::getChannelId, dto.getChannelId());
        //时间倒序
        lqw.orderByDesc(WmNews::getPublishTime);
        page = page(page, lqw);
        //结果返回
        ResponseResult result = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
        result.setData(page.getRecords());
        return result;
    }

    /**
     * 自媒体发布文章或保存草稿
     *
     * @param
     * @return
     */
    @Override
    public ResponseResult submitNews(WmNewsDto dto) {
        //条件判断
        if (dto == null || dto.getContent() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //存在,保存或修改文章
        WmNews wmNews = new WmNews();
        //将页面dto数据拷贝到wmnews(属性名和类型都相同才能拷贝)
        BeanUtils.copyProperties(dto, wmNews);
        //封面图片images[]-->string
        if (dto.getImages() != null && dto.getImages().size() > 0) {
            //设置了封面图片[asada.jpg,adsd.jpg]-->asada.jpg,adsd.jpg
            String images = StringUtils.join(dto.getImages(), ",");
            wmNews.setImages(images);
        }
        //如果当前封面类型为-1,自动匹配封面图片
        if (dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)) {
            wmNews.setType(null);
        }
        //保存或修改
        saveOrUpdateWmNews(wmNews);
        //判断是否为草稿,如果是草稿status=0;不用保存文章,封面,素材关系
        if (dto.getStatus().equals(WmNews.Status.NORMAL.getCode())) {
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }
        //不是草稿,需要保存文章内容图片与素材的关系以及封面图片与素材的关系
        //获取到文章内容中的图片信息
        List<String> materials = ectraactUrlInfo(dto.getContent());
        //素材图片与文章的关系
        saveRelativeInfoForContent(materials, wmNews.getId(), WemediaConstants.WM_CONTENT_REFERENCE);

        //封面图片与素材的关系;如果当前布局是自动，需要匹配封面图片
        saveRelativeInfoForCover(dto, wmNews, materials);
        //提交审核
        // wmNewsAutoScanService.autoScanWmNews(wmNews.getId());
        wmNewsTaskService.addNewsToTask(wmNews.getId(), wmNews.getPublishTime());
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }


    /**
     * 封面图片与素材的关系;自动匹配封面类型
     *
     * @param dto
     * @param wmNews
     * @param materials
     */
    private void saveRelativeInfoForCover(WmNewsDto dto, WmNews wmNews, List<String> materials) {
        List<String> images = dto.getImages();
        //type=-1自动匹配封面图片数量
        if (dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)) {
            //图片>=3多图
            if (materials.size() >= 3) {
                wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
                images = materials.stream().limit(3).collect(Collectors.toList());
            } else if (materials.size() >= 1 && materials.size() < 3) {
                //1-2单图
                wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
                images = materials.stream().limit(1).collect(Collectors.toList());
            } else {
                //0无图
                wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
            }
            //修改文章
            if (images != null && images.size() > 0) {
                wmNews.setImages(StringUtils.join(images, ","));
            }
            updateById(wmNews);
        }

        if (images != null && images.size() > 0) {
            //按指定规则匹配封面
            saveRelativeInfo(images, wmNews.getId(), WemediaConstants.WM_COVER_REFERENCE);
        }
    }

    /**
     * 处理文章内容图片和素材的关系
     *
     * @param materials 内容中的图片
     * @param wmNewsId  文章id
     */
    private void saveRelativeInfoForContent(List<String> materials, Integer wmNewsId, Short type) {
        saveRelativeInfo(materials, wmNewsId, type);
    }


    /**
     * 保存文章图片与素材的关系到数据库中
     *
     * @param materials
     * @param wmNewsId
     * @param type
     */
    private void saveRelativeInfo(List<String> materials, Integer wmNewsId, Short type) {
        if (materials != null && !materials.isEmpty()) {
            //通过图片的url查询素材id
            List<WmMaterial> wmMaterials = wmMaterialMapper.selectList(Wrappers
                    .<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, materials));
            //判断素材是否有效
            if (wmMaterials == null || wmMaterials.size() == 0) {
                throw new CustomException(AppHttpCodeEnum.MATERIASL_REFERENCE_FAIL);
            }
            //materials内容中的图片数量!=wmMaterials通过url在数据库中查到的图片
            if (materials.size() != wmMaterials.size()) {
                throw new CustomException(AppHttpCodeEnum.MATERIASL_REFERENCE_FAIL);
            }
            List<Integer> idList = wmMaterials.stream().map(WmMaterial::getId).collect(Collectors.toList());
            System.out.println("内容中图片id:" + idList);
            //批量保存
            wmNewsMaterialMapper.saveRelations(idList, wmNewsId, type);
        }
    }


    /**
     * 获取内容中的图片信息
     *
     * @param content
     */
    private List<String> ectraactUrlInfo(String content) {
        List<String> materials = new ArrayList<>();
        List<Map> list = JSON.parseArray(content, Map.class);
        for (Map map : list) {
            if (map.get("type").equals("image")) {
                String imageUrl = (String) map.get("value");
                materials.add(imageUrl);
            }
        }
        return materials;
    }

    /**
     * 执行保存或修改
     *
     * @param wmNews
     */
    private void saveOrUpdateWmNews(WmNews wmNews) {
        //补全属性
        wmNews.setUserId(WmThreadLocalUtil.getWmUserThreadLocal().getId());
        wmNews.setCreatedTime(new Date());
        wmNews.setSubmitedTime(new Date());
        wmNews.setEnable((short) 1);
        if (wmNews.getId() == null) {
            //不存在,保存
            save(wmNews);
        } else {
            //已存在,修改,删除文章图片与素材的关系,后续重新保存新关系
            wmNewsMaterialMapper.delete(Wrappers.
                    <WmNewsMaterial>lambdaQuery().
                    eq(WmNewsMaterial::getNewsId, wmNews.getId()));
            updateById(wmNews);
        }
    }

    @Autowired
    private KafkaTemplate kafkaTemplate;

    /**
     * wmmedia操作上下架
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult downOrUp(WmNewsDto dto) {
        //参数校验
        if (dto.getId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //根据id查询文章,是否存在;不存在,结束;存在继续
        if (getById(dto.getId()) == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "文章不存在");
        }
        //判断文章是否发布;未发布,结束;
        WmNews wmNews = getById(dto.getId());
        if (!wmNews.getStatus().equals(WmNews.Status.PUBLISHED.getCode())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "文章未发布,不能进行上下架");
        }
        //已发布,修改文章enable状态
        if (dto.getEnable() != null && dto.getEnable() > -1 && dto.getEnable() < 2) {
            update(Wrappers.<WmNews>lambdaUpdate().eq(WmNews::getId, wmNews.getId()).set(WmNews::getEnable, dto.getEnable()));
        }
        //kafka通知article端修改文章配置
        if (wmNews.getArticleId() != null) {
            Map<String, Object> map = new HashMap<>();
            map.put("articleId", wmNews.getArticleId());
            map.put("enable", wmNews.getEnable());
            kafkaTemplate.send(WmNewsMessageConstants.WM_NEWS_UP_OR_DOWN_TOPIC, JSON.toJSONString(map));
        }
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Autowired
    private WmUserService wmUserService;

    /**
     * 媒体审核
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult list_vo(PageRequestDto dto) {
        //参数校验
        dto.checkParam();
        //数据处理
        //执行分页;标题模糊查询;审核状态精确查询;创建时间倒序;展示作者名称
        Page<WmNews> page = new Page<>(dto.getPage(), dto.getSize());
        page = page(page, Wrappers.<WmNews>lambdaQuery()
                .like(dto.getTitle() != null, WmNews::getTitle, dto.getTitle())
                .eq(dto.getStatus() != null, WmNews::getStatus, dto.getStatus())
                .orderByDesc(WmNews::getCreatedTime));
        ResponseResult res = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
        List<WmNews> wmNews = page.getRecords();
        List<WmNewsVo> wmNewsVos = new ArrayList<>();

        for (WmNews wmNew : wmNews) {
            WmNewsVo wmNewsVo = new WmNewsVo();
            BeanUtils.copyProperties(wmNew, wmNewsVo);

            Integer userId = wmNew.getUserId();
            WmUser wmUser = wmUserService.getById(userId);
            wmNewsVo.setAuthorName(wmUser.getName());
            wmNewsVos.add(wmNewsVo);
        }
        res.setData(wmNewsVos);
        return res;
    }

    /**
     * 查询文章详情
     *
     * @param id
     * @return
     */
    @Override
    public ResponseResult one_vo(Integer id) {
        //参数校验
        if (getById(id) == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        WmNews wmNews = getById(id);
        WmUser wmUser = wmUserService.getById(wmNews.getUserId());
        WmNewsVo wmNewsVo = new WmNewsVo();
        BeanUtils.copyProperties(wmNews, wmNewsVo);
        wmNewsVo.setAuthorName(wmUser.getName());
        return ResponseResult.okResult(wmNewsVo);
    }

    /**
     * 审核失败
     *
     * @param map
     * @return
     */
    @Override
    public ResponseResult auth_fail(Map<String, String> map) {
        String id = map.get("id");
        String msg = map.get("title");
        if (StringUtils.isBlank(id) || StringUtils.isBlank(msg)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        WmNews wmNews = getById(id);
        wmNews.setStatus((short) 2);
        wmNews.setReason(msg);
        updateById(wmNews);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 人工审核成功
     *
     * @param map
     * @return
     */
    @Override
    public ResponseResult auth_pass(Map<String, String> map) {
        String id = map.get("id");
        if (StringUtils.isBlank(id)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        WmNews wmNews = getById(id);
        //审核完成,保存APP端的相关数据
        ResponseResult result = wmNewsAutoScanService.saveAppArticle(wmNews);
        if (!result.getCode().equals(200)) {
            throw new RuntimeException("文章审核,保存app端相关数据失败");
        }
        //在news中回填article_id
        Long articleId = (long) result.getData();
        wmNews.setArticleId(articleId);
        wmNews.setStatus((short) 4);
        wmNews.setReason("人工审核成功");
        //获取发布时间,发送延迟消息,更改发布状态
        //延迟发布
        Message msg = MessageBuilder.withBody(wmNews.getId().toString().getBytes(StandardCharsets.UTF_8))
                .setHeader("x-delay", 15000)
                .build();
        rabbitTemplate.convertAndSend("delay.direct", "delay", msg);
        log.info("延迟消息发送成功{}", msg);
        updateById(wmNews);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
}
